/*
 *  alogd.c
 *
 *  Copyright (C) 2011  Peter Polacik <polacik.p@gmx.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* Program includes */
#include "alogd.h"
#include "uthash.h"

/* Library includes */
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

int sockfd;
appl_t *applist = NULL;
char *sockpath;

void errorize(char *s, int ec)
{
	fprintf(stderr, "E: %s\n", s);
	exit(ec);
}

int addapp(char *name, char *logdir)
{
	appl_t *s;
	int fd, errnumber, sz;
	char *logfile;
	sz = strlen(logdir) + strlen(name) + strlen("/.log") + 1;
#ifdef DEBUG
	fprintf(stderr, "[DEBUG] addapp:sz : %d\n", sz);
#endif
	logfile = (char *)malloc(sz);
	if (logfile == NULL)
		errorize("addapp:logfile allocation", E_ALLOC);
	strcpy(logfile, logdir);
	strcat(logfile, "/");
	strcat(logfile, name);
	strcat(logfile, ".log");
#ifdef DEBUG
	fprintf(stderr, "[DEBUG] logfile @ %p : \'%s\'\n", logfile, logfile);
	fprintf(stderr, "[DEBUG] name @ %p : \'%s\'\n", name, name);
#endif
	fd = open(logfile, O_WRONLY | O_CREAT | O_APPEND, 
		  S_IRUSR | S_IWUSR | S_IRGRP);
	if (fd == -1) {
		errnumber = errno;
		free(logfile);
		errorize(strerror(errnumber), E_LOGOPEN);
	}
	s = malloc(sizeof(appl_t));
	if (s == NULL)
		return -1;
	s->name = name;
	s->fd = fd;
	HASH_ADD_KEYPTR(hh, applist, s->name, strlen(s->name), s);
	return s->fd;
}

int getfd(char *name)
{
	appl_t *s;
	HASH_FIND_STR(applist, name, s);
#ifdef DEBUG
	/*fprintf(stderr, "[DEBUG] s @ %p : s->fd : %d\n", s, s->fd);*/
#endif
	if (s) return s->fd;
	else return -1;
}

int clearappl(void)
{
	appl_t *s, *tmp;
	HASH_ITER(hh, applist, s, tmp) {
#ifdef DEBUG
		fprintf(stderr, "[DEBUG] deleting item: %s : %d\n",
			s->name, s->fd);
#endif
		HASH_DEL(applist, s);
		free(s);
	}
	return 0;
}

int removeapp(char *name)
{
	appl_t *s;
	HASH_FIND_STR(applist, name, s);
	if (s) {
		close(s->fd);
		HASH_DEL(applist, s);
		free(s);
		return 0;
	} else return -1;
}

char *fixname(char *s, char rletter)
{
	unsigned int i;
	for (i = 0; i < strlen(s); i++) {
		if (s[i] == '/' || s[i] == '.' || s[i] == ';')
			s[i] = rletter;
	}
	return s;
}

void quit(int signo)
{
	close(sockfd);
	clearappl();
	unlink(sockpath);
	printf("Received signal: %s\nQuitting...\n", strsignal(signo));
	exit(0);
}

int main(int argc, char **argv)
{
	char *progname = argv[0];
	char *conffile = DEFAULT_CONFFILE;
	conf_t *configfile;
	conf_t settings = { NULL, NULL, 0 };
	if (argc > 1) {
		struct option long_opt[] = {
			{ "help",	0, NULL, 'h' },
			{ "usage",	0, NULL, 'u' },
			{ "config",	1, NULL, 'c' },
			{ "backlog",	1, NULL, 'b' },
			{ "directory",	1, NULL, 'd' },
			{ "socket",	1, NULL, 's' },
			/*{ "server",	1, NULL, 'S' },*/
			{ NULL,		0, NULL, 0   }
		};
		/* 
		 * FIXME: When support for server flag is available,
	 	 *	  add it into short_opt
	 	 */
		const char *const short_opt = "huc:b:d:s:"; 
		int next_opt;
		do {
			next_opt = getopt_long(argc, argv, short_opt,
						long_opt, NULL);
			switch (next_opt) {
				case 'h' : printusage(progname, stdout,
							E_SUCC, 1);
					break;
				case 'u' : printusage(progname, stdout,
							E_SUCC, 0);
					break;
				case 'c' : /* Set config file */
					conffile = optarg;
#ifdef DEBUG
					fprintf(stderr, "[DEBUG] conffile"
						" @ %p : \'%s\'\n",
						conffile, conffile);
#endif
					break;
				case 'b' : /* Set backlog */
					sscanf(optarg, "%d",
						&(settings.backlog));
#ifdef DEBUG
					fprintf(stderr, "[DEBUG] backlog"
						" : %d\n",
						settings.backlog);
#endif
					break;
				case 'd' : /* Set logging dir */
					settings.logdir = optarg;
#ifdef DEBUG
					fprintf(stderr, "[DEBUG] logdir"
						" @ %p : \'%s\'\n",
						settings.logdir,
						settings.logdir);
#endif
					break;
				case 's' : /* Set socket file */
					settings.sockpath = optarg;
#ifdef DEBUG
					fprintf(stderr, "[DEBUG] sockpath"
						" @ %p : \'%s\'\n",
						settings.sockpath,
						settings.sockpath);
#endif
					break;
				case -1 :
					break;
				default : printusage(progname, stderr,
							E_INVARG, 0);
					break;
			}
		} while (next_opt != -1);
	}
	signal(SIGINT, quit);
	signal(SIGSEGV, quit);
	configfile = parse(conffile);
	if (settings.backlog == 0)
		settings.backlog = configfile->backlog;
	if (settings.logdir == NULL)
		settings.logdir = configfile->logdir;
	if (settings.sockpath == NULL)
		settings.sockpath = configfile->sockpath;
	sockpath = settings.sockpath;
#ifdef DEBUG
	fprintf(stderr, "[DEBUG] backlog : %d\n", settings.backlog);
	fprintf(stderr, "[DEBUG] logdir @ %p : \'%s\'\n", settings.logdir,
		settings.logdir);
	fprintf(stderr, "[DEBUG] sockpath @ %p : \'%s\'\n", settings.sockpath,
		settings.sockpath);
#endif

/*	free(configfile->logdir);
	free(configfile->sockpath);
	free(configfile);
*/
	printf("ALOGD_SOCK=%s; export ALOGD_SOCK;\n", settings.sockpath);
	/* TODO: Finish */
	while (1) recv_local(&settings);
	return 0;
}
